﻿using System;
using System.Collections.Generic;

namespace Ewk.Configuration
{
    /// <summary>
    /// Interface that defines a DependencyContainer.
    /// </summary>
    public interface IDependencyResolver : IDisposable
    {
        /// <summary>
        /// Resolves the registered instance of <see cref="Type"/> <paramref name="type"/>.
        /// </summary>
        /// <param name="type">The registered <see cref="Type"/> to resolve.</param>
        /// <param name="parameterOverrides">The <see cref="DependencyResolverParameterOverride"/> instances to override default values for parameters.</param>
        /// <returns>An instance of the requested <see cref="Type"/>.</returns>
        object Resolve(Type type, params DependencyResolverParameterOverride[] parameterOverrides);

        /// <summary>
        /// Resolves an instance of the requested type with the given name.
        /// </summary>
        /// <param name="type">The registered <see cref="Type"/> to resolve.</param>
        /// <param name="name">Name of the object to retrieve.</param>
        /// <param name="parameterOverrides">The <see cref="DependencyResolverParameterOverride"/> instances to override default values for parameters.</param>
        /// <returns>An instance of the requested <see cref="Type"/>.</returns>
        object Resolve(Type type, string name, params DependencyResolverParameterOverride[] parameterOverrides);

        /// <summary>
        /// Resolves all registered instances of <see cref="Type"/> <paramref name="type"/>.
        /// </summary>
        /// <param name="type">The registered <see cref="Type"/> to resolve.</param>
        /// <returns>A list of instances of the requested <see cref="Type"/>.</returns>
        /// <remarks>
        /// This method is useful if you've registered multiple types with the same Type but different names. 
        /// Be aware that this method does NOT return an instance for the default (unnamed) registration.
        /// </remarks>
        IEnumerable<object> ResolveAll(Type type);

        /// <summary>
        /// Resolves the registered instance of <see cref="Type"/> <typeparamref name="TReturn"/>.
        /// </summary>
        /// <param name="parameterOverrides">The <see cref="DependencyResolverParameterOverride"/> instances to override default values for parameters.</param>
        /// <typeparam name="TReturn">The registered <see cref="Type"/> to resolve.</typeparam>
        /// <returns>An instance of <see cref="Type"/> <typeparamref name="TReturn"/>.</returns>
        TReturn Resolve<TReturn>(params DependencyResolverParameterOverride[] parameterOverrides)
            where TReturn : class;

        /// <summary>
        /// Resolves the registered instance of <see cref="Type"/> <typeparamref name="TReturn"/> with the given name.
        /// </summary>
        /// <typeparam name="TReturn">The registered <see cref="Type"/> to resolve.</typeparam>
        /// <param name="name">Name of the object to retrieve.</param>
        /// <param name="parameterOverrides">The <see cref="DependencyResolverParameterOverride"/> instances to override default values for parameters.</param>
        /// <returns></returns>
        TReturn Resolve<TReturn>(string name, params DependencyResolverParameterOverride[] parameterOverrides)
            where TReturn : class;

        /// <summary>
        /// Resolves all instances of <see cref="Type"/> <typeparamref name="TReturn"/>.
        /// </summary>
        /// <typeparam name="TReturn">The registered <see cref="Type"/> to resolve.</typeparam>
        /// <returns>A list of instance of <see cref="Type"/> <typeparamref name="TReturn"/>.</returns>
        /// <remarks>
        /// This method is useful if you've registered multiple types with the same Type but different names. 
        /// Be aware that this method does NOT return an instance for the default (unnamed) registration.
        /// </remarks>
        IEnumerable<TReturn> ResolveAll<TReturn>()
            where TReturn : class;

        /// <summary>
        /// Run an existing object through the container, and clean it up.
        /// </summary>
        /// <param name="o">The object to tear down.</param>
        void Teardown(object o);

        /// <summary>
        /// Ensures that an instance of <see cref="Type"/> <typeparamref name="TFrom"/>
        /// can be resolved and returns an instance of <see cref="Type"/> <typeparamref name="TTo"/>.
        /// </summary>
        /// <typeparam name="TFrom">The <see cref="Type"/> that will be resolved.</typeparam>
        /// <typeparam name="TTo">The <see cref="Type"/> that should be returned when <typeparamref name="TFrom"/> is resolved.</typeparam>
        void EnsureIsRegistered<TFrom, TTo>()
            where TTo : TFrom;
    }
}